﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using Infrastucture;
using TimeSplicerModule.Factories;
using TimeSplicerModule.DomainModels;
using TimeSplicerModule.Security;
using TimeSplicerModule.ViewModels;

namespace TimeSplicerModule.Services
{
    public interface IUserService
    {
        UserViewModel CreateNew();
        UserViewModel Get(Guid userGuid);
        UserViewModel Save(UserViewModel model);
        UserModel Search(string fullName);
        UserListViewModel GetListViewModel();
        List<UserModel> GetProjectInvitableUsers();
        List<UserModel> GetViewableUsers();
        List<UserModel> GetSelectableProjectManagers();
    }

    public class UserService : IUserService
    {
        private readonly IUnityContainer _container;
        private ISession _session;
        private readonly IUserFactory _userFactory;
        private readonly ITeamService _teamService;
        private readonly ITeamFactory _teamFactory;
        private readonly IApplicationRoleFactory _appRoleFactory;
        private readonly IApplicationRoleService _applicationRoleService;
        private readonly IStatusFactory _statusFactory;
        

        public UserService(IUnityContainer container, IUserFactory userFactory,
             ITeamService teamService, ITeamFactory teamFactory, IApplicationRoleFactory appRoleFactory,
            IApplicationRoleService applicationRoleService,
            IStatusFactory statusFactory)
        {
            _container = container;
            _userFactory = userFactory;
            _teamService = teamService;
            _teamFactory = teamFactory;
            _appRoleFactory = appRoleFactory;
            _applicationRoleService = applicationRoleService;
            _statusFactory = statusFactory;
        }

        public UserViewModel CreateNew()
        {
            _session = _container.Resolve<ISession>();

            // may add a heirarchical positioning

            var statuses = _statusFactory.GetList(x => x.IsUserStatus);
            var myTeams = _teamService.GetViewableTeams();
            var appRoles = _appRoleFactory.GetList(x => x.Hierarchy >=
                _session.User.ApplicationRole.Hierarchy);

            var user = _userFactory.CreateNew(statuses,
                appRoles, myTeams);


            // set defaiults
            user.Statuses = statuses;
            var active = statuses.FirstOrDefault(x => x.Status == Status.Active);
            user.StatusGuid = active.StatusGuid;
            user.Status = active;

            user.Teams = myTeams;
            user.Team = myTeams.OrderBy(o => o.Y).FirstOrDefault();
            user.TeamGuid = user.Team.TeamGuid;

            user.ApplicationRoles = appRoles;
            // default to last hierarchical user
            user.ApplicationRole = appRoles.OrderByDescending(o => o.Hierarchy).FirstOrDefault();
            user.ApplicationRoleGuid = user.ApplicationRole.ApplicationRoleGuid;
            

            // convert to view model
            var model = ModelConverter.ToModel<UserViewModel>(user);



            return model;
        }


        public UserViewModel Get(Guid userGuid)
        {
            _session = _container.Resolve<ISession>();

            var user = _userFactory.Get(x => x.UserGuid == userGuid);
            var statuses = _statusFactory.GetList(x => x.IsUserStatus);
            var myTeams = _teamService.GetViewableTeams();
            var appRoles = _appRoleFactory.GetList(x => x.Hierarchy >=
                _session.User.ApplicationRole.Hierarchy);


            // set values
            user.Statuses = statuses;
            user.Status = statuses.FirstOrDefault(x => x.StatusGuid == user.StatusGuid);

            user.Teams = myTeams;
            user.Team = myTeams.FirstOrDefault(x => x.TeamGuid == user.TeamGuid);

            user.ApplicationRoles = appRoles;
            user.ApplicationRole = appRoles.FirstOrDefault(x => x.ApplicationRoleGuid == user.ApplicationRoleGuid);

            var model = ModelConverter.ToModel<UserViewModel>(user);


            return model;
        }

        public UserViewModel Save(UserViewModel model)
        {
            _session = _container.Resolve<ISession>();

            var user = ModelConverter.ToModel<UserModel>(model);

            user = _userFactory.Upsert(user);


            return Get(user.UserGuid);
        }

        public UserListViewModel GetListViewModel()
        {
            _session = _container.Resolve<ISession>();

            UserListViewModel model = new UserListViewModel();
            model.Users = GetViewableUsers();


            return model;
        }

        public List<UserModel> GetProjectInvitableUsers()
        {
            _session = _container.Resolve<ISession>();

            // this will be all users, just need there names really no need to get nested classes
            // get all users not equal to session user

            var users = _userFactory.GetList(x => x.UserGuid != _session.User.UserGuid);

            return users;
        }

        public List<UserModel> GetViewableUsers()
        {
            _session = _container.Resolve<ISession>();
            List<UserModel> viewableUsers = new List<UserModel>();

            // need to get statuses, teams, app roles
            var statuses = _statusFactory.GetList(x => x.IsUserStatus);
            var teams = _teamFactory.GetList();
            var appRoles = _appRoleFactory.GetList();
            //var appPermissions = _appPermissionFactory.GetList();
          
            

            // need to get users whos role is of hierarchy of less then current
            var users = _userFactory.GetList();

            foreach (var u in users)
            {
                u.ApplicationRole = appRoles.FirstOrDefault(x => x.ApplicationRoleGuid == u.ApplicationRoleGuid);
                //u.ApplicationRole.Permissions = appPermissions;

                if (_session.User.ApplicationRole.Hierarchy < u.ApplicationRole.Hierarchy 
                    || u.UserGuid == _session.User.UserGuid)
                {
                    u.Team = teams.FirstOrDefault(x => x.TeamGuid == u.TeamGuid);
                    u.Status = statuses.FirstOrDefault(x => x.StatusGuid == u.StatusGuid);

                    viewableUsers.Add(u);
                }
            }



            return viewableUsers;
        }


        public UserModel Search(string fullName)
        {
            throw new NotImplementedException();
        }


        public List<UserModel> GetSelectableProjectManagers()
        {
            _session = _container.Resolve<ISession>();
            List<UserModel> selectableUsers = new List<UserModel>();
            var users = _userFactory.GetList();

            var statuses = _statusFactory.GetList(x => x.IsUserStatus);
            var teams = _teamFactory.GetList();
            var appRoles = _appRoleFactory.GetList();
            var pm = appRoles.FirstOrDefault(x => x.Name == "Project Manager");

            foreach (var u in users)
            {
                u.ApplicationRole = appRoles.FirstOrDefault(x => x.ApplicationRoleGuid == u.ApplicationRoleGuid);

                if (_session.User.ApplicationRole.Hierarchy <= pm.Hierarchy
                    || u.UserGuid == _session.User.UserGuid)
                {
                    u.Team = teams.FirstOrDefault(x => x.TeamGuid == u.TeamGuid);
                    u.Status = statuses.FirstOrDefault(x => x.StatusGuid == u.StatusGuid);

                    selectableUsers.Add(u);
                }
            }


            return selectableUsers;
        }
    }
}
